//////////////////////////////////////////////////////////////////////////
//	File	:	"MathHelper.cpp"
//
//	Author	:	David Brown (DB)
//
//	Purpose	:	To do lots of math for us.
///////////////////////////////////////////////////////////////////////////
#include "MathHelper.h"
#include <math.h>	//	for sqrt()
#include <float.h>	//	for fabs() and _isnan()
#include "../headers/Game.h"

//RECT & tagRECTF::operator=(RECT & r, tagRECTF & rect)
//{
//	RECT r;
//	r.top = (LONG)rect.top;
//	r.right = (LONG)rect.right;
//	r.bottom = (LONG)rect.bottom;
//	r.left = (LONG)rect.left;
//
//	return r;
//}
//	Find the length of a vector (magnitude)
float Vector2DLength(vector2D vec)
{
	//	A^2 + B^2 = C^2
	//	C = sqrt(A^2 + B^2)
	return sqrt( (vec.fX * vec.fX) + (vec.fY * vec.fY) );
}

// Find the dot product
float DotProduct(vector2D v1, vector2D v2)
{
	//	(a.x * b.x) + (a.y * b.y)
	return (v1.fX * v2.fX) + (v1.fY * v2.fY);
}

//	Normalize a vector
vector2D Vector2DNormalize(vector2D vec)
{
	float fLength = Vector2DLength(vec);

	vector2D vNormalized = vec / fLength;

	//	Return the normalized vector
	return vNormalized;
}

vector2D MidPoint(vector2D v1, vector2D v2)
{
	return vector2D((v1.fX + v2.fX) * 0.5f, (v1.fY + v2.fY) * 0.5f);
}

//	Rotate a vector
/*
	X, Y	=	[X]
				[Y]
				[1]

	[	cos&	sin&	0	]		[X]		[X1]
	[  -sin&	cos&	0	]	*	[Y]	=	[Y1]
	[	0		0		1	]		[1]		[1]
*/
vector2D Vector2DRotate(vector2D vec, float fRadians)
{
	//	Convert into the Cartesian coordinate system
	vec.fY *= -1.0f;

	vector2D vRotated;
	vRotated.fX = (cos(fRadians) * vec.fX) + (sin(fRadians) * vec.fY);
	vRotated.fY = (-sin(fRadians) * vec.fX) + (cos(fRadians) * vec.fY);

	//	Convert back to our windows coordinate system
	vRotated.fY *= -1.0f;

	//	Return our rotated vector
	return vRotated;
}
//	Find the angle between 2 vectors
float AngleBetweenVectors(vector2D v1, vector2D v2)
{
	//	Dot product
	float fDot = DotProduct(v1, v2);

	//	Length of those vectors
	float fLength =  Vector2DLength(v1) * Vector2DLength(v2);

	//	Make sure we don't get a divide by zero error.
	if (fLength == 0.0f)	return 0.0f;

	//	Calculate the angle between the two vectors
	float fAngle = acos( fDot / fLength );

	//	Make sure the number is not indefinite.  Shows up as -1.#IND00000.  Not a number.
	if (_isnan(fAngle))
		return 0.0f;

	//	Return the angle.
	return fAngle;
}



//	Tests if two floats are approximately equal given a margin of error
bool FloatEquals(float fResult, float fExpected, float fEpsilon)
{
	return (fabs(fResult - fExpected) < fEpsilon);
}

// Converts Seconds to hours and minutes
void SecondsToStandard(unsigned int nSecondsToConvert, int & nHours, int & nMins, int & nSecs)
{
	int tempForMins = nSecondsToConvert % 3600;
	if(tempForMins > 1)
	{
		nHours = nSecondsToConvert / 3600;
		tempForMins = nSecondsToConvert - (nHours * 3600);
	}
	if(tempForMins % 60 > 1)
	{
		nMins = tempForMins / 60;
	}
	nSecs = nSecondsToConvert - (nHours * 3600) - (nMins * 60);

}


//	Determines which way to turn (clockwise or counter-clockwise)
float Steering(vector2D vOrientation, vector2D vToTarget)
{
	//	Uses the Z-component of the cross product
	return (vOrientation.fX * vToTarget.fY) - (vOrientation.fY * vToTarget.fX);
}



bool BitOn(unsigned int & value, unsigned int flag)		{ return (value & flag) > 0; }
void TurnBitOn(unsigned int & value, unsigned int flag)	{ value |= flag; }
void TurnBitOff(unsigned int & value, unsigned int flag){ value &= ~flag; }
void ToggleBit(unsigned int & value, unsigned int flag)	{ value ^= flag; }

bool PointInTriangle(float x, float y, TRI_SHAPE & tri)
{
   return false;
}

//Helper function to determine if a point exists within a rectangle
bool PointInRect(int x, int y, RECT & rect)
{
	return x > rect.left && x < rect.right && y > rect.top && y < rect.bottom;
}

bool PointInRect(float x, float y, RECTF & rect)
{
	return x > rect.left && x < rect.right && y > rect.top && y < rect.bottom;
}


// Helper function to determine if a point exists within a circle
bool PointInCircle(int x, int y, int centerX, int centerY, int radius)
{
   return (((x - centerX) * (x - centerX)) + ((y - centerY) * (y - centerY)) < (radius * radius));
}

bool PointInCircle(float x, float y, float centerX, float centerY, float radius)
{
   return (((x - centerX) * (x - centerX)) + ((y - centerY) * (y - centerY)) < (radius * radius));
}

// Helper function to determine if a point exists with a hexagon
bool PointInHexagon(float x, float y, HEX_SHAPE & hex)
{
   // Early Out
   if (PointInCircle(x, y, hex.centerX, hex.centerY, hex.centerY - hex.top))
   {
      // Check the rectangle within the hexagon and the Triangles on the top and bottom of the rectangle
      if(PointInRect(x, y, RECTF(hex.left, hex.topMiddle, hex.right, hex.bottomMiddle)) ||
         PointInTriangle(x, y, TRI_SHAPE(vector2D(hex.right - hex.centerX, hex.top), vector2D(hex.left, hex.topMiddle), vector2D(hex.right, hex.topMiddle))) ||
         PointInTriangle(x, y, TRI_SHAPE(vector2D(hex.right - hex.centerX, hex.bottom), vector2D(hex.left, hex.bottomMiddle), vector2D(hex.right, hex.bottomMiddle))))
      {
         return true;
      }
      return false;
   }
   return false;
   //return (PointInRect(x, y, rect1) && PointInRect(x, y, rect2) && PointInRect(x, y, rect3));
}

float RandomFloat(float min, float max)
{
	return (rand() / ((float)RAND_MAX + 1.0f)) * (max - min) + min;
}

int RandomInt(int min, int max)
{
	if(min == max)
		return min;
	return (rand() % (max - min)) + min;
}
bool CheckCircleCollision(vector2D& vA, double radA, vector2D& vB, double radB)
{
	float nDistance = Vector2DDistance(vA, vB);

	return nDistance <= radA+radB;
}


RECT ScreenPercentsToRect(float left, float top, float width, float height)
{
	RECT r;
	int screenWidth = CGame::GetInstance()->GetScreenWidth();
	int screenHeight = CGame::GetInstance()->GetScreenHeight();

	r.left = (LONG)(screenWidth * left);
	r.right = (LONG)(screenWidth * width + r.left);
	r.top = (LONG)(screenHeight * top);
	r.bottom = (LONG)(screenHeight * height + r.top);

	return r;
}

DWORD LerpColor(DWORD startColor, DWORD endColor, float percent)
{
	unsigned char * start = (unsigned char*)&startColor;
	unsigned char * end = (unsigned char*)&endColor;
	
	DWORD color = 0;
	unsigned char * result = (unsigned char*)&color;

	result[0] = Lerp<unsigned char>(start[0], end[0], percent);
	result[1] = Lerp<unsigned char>(start[1], end[1], percent);
	result[2] = Lerp<unsigned char>(start[2], end[2], percent);
	result[3] = Lerp<unsigned char>(start[3], end[3], percent);

	return color;
}